// Copyright (c) Microsoft
// All rights reserved
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.

/// <summary><![CDATA[Copy involving const array<T, N> and const array view<T,N> for each API]]></summary>
// RUN: %amp_device -D__GPU__ %s -m32 -emit-llvm -c -S -O3 -o %t.ll && mkdir -p %t
// RUN: %llc -march=c -o %t/kernel_.cl < %t.ll
// RUN: cat %opencl_math_dir/opencl_math.cl %t/kernel_.cl > %t/kernel.cl
// RUN: pushd %t && objcopy -B i386:x86-64 -I binary -O elf64-x86-64 kernel.cl %t/kernel.o && popd
// RUN: %cxxamp %link %t/kernel.o %s -o %t.out && %t.out
#include <amp.h>
#include "../../../amp.compare.h"
#include "../../../../device.h"
using namespace Concurrency;
using namespace Concurrency::Test;

using std::vector;

unsigned int size = 10;

int Array_to_array(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	const array<int, 2> src(e, src_v.begin(), av);
	array<int, 2> dst(e);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	const array<int, 2> src(e, src_v.begin(), av);
	
	array<int, 2> data(e);
	const array_view<int, 2> dst(data);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_to_iter(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	const array<int, 2> src(e, src_v.begin(), av);
	
	vector<int> dst(e.size());
	
	copy(src, dst.begin());
    
	return VerifyDataOnCpu(src, dst);
}

int Const_iter2_to_array(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src(e.size(), 10);
	array<int, 2> dst(e, av);
	
	copy(src.cbegin(), src.cend(), dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Const_iter_to_array(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src(e.size(), 10);
	array<int, 2> dst(e, av);
	
	copy(src.cbegin(), dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_view_const_to_array(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	array<int, 2> data(e, src_v.begin(), av);
	const array_view<const int, 2> src(data);
	
	array<int, 2> dst(e);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_view_const_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	array<int, 2> data1(e, src_v.begin(), av);
	const array_view<const int, 2> src(data1);
	
	array<int, 2> data2(e);
	const array_view<int, 2> dst(data2);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_view_to_array(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	array<int, 2> data(e, src_v.begin(), av);
	const array_view<int, 2> src(data);
	
	array<int, 2> dst(e);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_view_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	array<int, 2> data1(e, src_v.begin(), av);
	const array_view<int, 2> src(data1);
	
	array<int, 2> data2(e);
	const array_view<int, 2> dst(data2);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_view_to_iter(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	array<int, 2> data(e, src_v.begin(), av);
	const array_view<int, 2> src(data);
	
	vector<int> dst(e.size());
	
	copy(src, dst.begin());
    
	return VerifyDataOnCpu(src, dst);
}

int Iter2_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src(e.size(), 10);
	
	array<int, 2> data(e, av);
	const array_view<int, 2> dst(data);
	
	copy(src.begin(), src.end(), dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Iter_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src(e.size(), 10);
	
	array<int, 2> data(e, av);
	const array_view<int, 2> dst(data);
	
	copy(src.begin(), dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Const_iter2_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src(e.size(), 10);
	
	array<int, 2> data(e, av);
	const array_view<int, 2> dst(data);
	
	copy(src.cbegin(), src.cend(), dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Const_iter_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src(e.size(), 10);
	
	array<int, 2> data(e, av);
	const array_view<int, 2> dst(data);
	
	copy(src.cbegin(), dst);
    
	return VerifyDataOnCpu(src, dst);
}

int Array_to_const_pointer(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	const array<int, 2> src(e, src_v.begin(), av);
	
	vector<int> dst_v(e.size());
	int* const dst = dst_v.data();
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst_v);
}

int Const_pointer_to_array(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	int* const src = src_v.data();
	
	array<int, 2> dst(e, av);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src_v, dst);
}

int Array_view_to_const_pointer(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	array<int, 2> data(e, src_v.begin(), av);
	const array_view<int, 2> src(data);
	
	vector<int> dst_v(e.size());
	int* const dst = dst_v.data();
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src, dst_v);
}

int Const_pointer_to_array_view(accelerator_view& av)
{
	extent<2> e(size, size);
    
    vector<int> src_v(e.size(), 10);
	int* const src = src_v.data();
	
	array<int, 2> data(e, av);
	const array_view<int, 2> dst(data);
	
	copy(src, dst);
    
	return VerifyDataOnCpu(src_v, dst);
}


int main()
{
	accelerator_view av = require_device().get_default_view();
	
	int result = 1;

	result &= Array_to_array(av);
	result &= Array_to_array_view(av);
	result &= Array_to_iter(av);
	result &= Const_iter2_to_array(av);
	result &= Const_iter_to_array(av);
	result &= Array_view_const_to_array(av);
	result &= Array_view_const_to_array_view(av);
	result &= Array_view_to_array(av);
	result &= Array_view_to_array_view(av);
	result &= Array_view_to_iter(av);
	result &= Iter2_to_array_view(av);
	result &= Iter_to_array_view(av);
	result &= Const_iter2_to_array_view(av);
	result &= Const_iter_to_array_view(av);
	result &= Array_to_const_pointer(av);
	result &= Const_pointer_to_array(av);
	result &= Array_view_to_const_pointer(av);
	result &= Const_pointer_to_array_view(av);

	return !result;
}

